#include "packet/packet.h"
#include "packet/cmd_packet.h"
#include "base/util_string.h"

//cmd packet
static const char const_cmd_enter_char = '\r';
static const char const_cmd_newline_char = '\n';
static const char  const_cmd_colon_char = ':';
static const char  const_cmd_enter_newline_str[] = { '\r', '\n' };
static const char* const const_cmd_length_key = "Length";
static const char* const const_cmd_command_key = "Command";
static const char* const const_cmd_seq_key = "Seq";

namespace weilin {

	CmdPacket::CmdPacket() :
		m_consumer_status(CMD_IDLE)
	{
		m_head.Reset();
	}
	CmdPacket::~CmdPacket()
	{
		m_head.Reset();
	}

	bool CmdPacket::Tobuffer(string& outBuffStr)
	{
		outBuffStr.clear();
		if (m_is_only_body == true)
		{
			outBuffStr.append(m_body);
		}
		else
		{
			string cmd_length_value = boost::lexical_cast<string>(m_body.length());
			SetKeyValue(const_cmd_length_key, cmd_length_value);
			for (map<string, string>::iterator index_it = m_head_map.begin(); index_it != m_head_map.end(); index_it++)
			{
				outBuffStr.append(index_it->first);
				outBuffStr.push_back(const_cmd_colon_char);
				outBuffStr.append(index_it->second);
				outBuffStr.append(const_cmd_enter_newline_str);
			}
			outBuffStr.append(const_cmd_enter_newline_str);
			outBuffStr.append(m_body);

		}
		return true;
	}

	ConsumerRetStatus CmdPacket::Consume(const char& input)
	{
		m_recv_str.push_back(input);
 		switch (m_consumer_status)
		{
		case CMD_IDLE:
		case CMD_KEY:
		{
			if (input == const_cmd_colon_char)
			{
				m_consumer_status = CMD_VALUE;
				return CONSUM_RET_CONTINUE;
			}
			if (input == const_cmd_enter_char)
			{
				m_consumer_status = CMD_NEW_LINE_BODY_CHAR;
				return CONSUM_RET_CONTINUE;
			}
			if (is_ctl(input) || is_tspecial(input))
			{
				return CONSUM_RET_FAIL;
			}
			m_head.key.push_back(input);
			return CONSUM_RET_CONTINUE;
		}
		case CMD_VALUE:
		{
			if (input == const_cmd_enter_char)
			{
				m_consumer_status = CMD_NEW_LINE_HEAD_CHAR;
				//already has the key err
				if (m_head_map.find(m_head.key) != m_head_map.end())
				{
					return CONSUM_RET_FAIL;
				}
				SetKeyValue(m_head.key, m_head.value);
				m_head.Reset();
				return CONSUM_RET_CONTINUE;
			}
			if (is_ctl(input) || is_tspecial(input))
			{
				return CONSUM_RET_FAIL;
			}
			m_head.value.push_back(input);
			return CONSUM_RET_CONTINUE;
		}
		case CMD_NEW_LINE_HEAD_CHAR:
		{
			if (input != const_cmd_newline_char)
			{
				return CONSUM_RET_FAIL;
			}
			m_consumer_status = CMD_KEY;
			return CONSUM_RET_CONTINUE;
		}
		case CMD_NEW_LINE_BODY_CHAR:
		{
			if (input != const_cmd_newline_char)
			{
				return CONSUM_RET_FAIL;
			}

			bool ret = false;
			string temp_value;
			ret = GetKeyValue(const_cmd_length_key, temp_value);
			if (ret == false)
			{
				return CONSUM_RET_FAIL;
			}
			m_remain_body_length = boost::lexical_cast<int>(temp_value);
			if (m_remain_body_length <= 0)
			{
				return CONSUM_RET_FAIL;
			}

			if (GetKeyValue(const_cmd_command_key, m_cmd) == true)
			{
				m_is_request = true;
			}

			if (GetKeyValue(const_cmd_seq_key, temp_value) == true)
			{
				m_seq = boost::lexical_cast<uint32_t>(temp_value);
			}

			m_consumer_status = CMD_BODY;
			return CONSUM_RET_CONTINUE;
		}
		case CMD_BODY:
		{
			m_body.push_back(input);
			m_remain_body_length--;
			if (m_remain_body_length == 0)
			{
				return CONSUM_RET_SUCCESS;
			}
			return CONSUM_RET_CONTINUE;
		}
		default:
		{
			return CONSUM_RET_FAIL;
		}
		}
	}
}
